package com.ideal.manage.esms.service.monitor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.ideal.manage.esms.bean.project.EquipmentManage;
import com.ideal.manage.esms.jpa.JpaRepositoryImpl;
import com.ideal.manage.esms.service.ElasticsearchService;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class MonitorPackageHistoryService {
    private JpaRepositoryImpl<EquipmentManage, String> equipmentManageRepository;
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private ElasticsearchService elasticsearchService;

    @PostConstruct
    public void init() {
        this.equipmentManageRepository = new JpaRepositoryImpl<>(EquipmentManage.class, entityManager);
    }

    /**
     * 历史数据
     *
     * @param id        设备id
     * @param objType   测点类别
     * @param name      测点名称
     * @param ranges    时间范围
     * @param frequency 显示密度 小时 15分钟
     * @param showType  显示类别 //平均值，最大值 最小值 当前无效
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public JSONObject historyPackageDataEquipment(String id, int objType, String name, String ranges,
                                                  String frequency, String showType, String startTime, String endTime) {
        JSONObject r = new JSONObject();
        // 2. 获取当前设备
        EquipmentManage equipmentManage = equipmentManageRepository.findOne(id);
        if (equipmentManage == null) {
            return r;
        }
        // 4. 获取时间
        Tuple<LocalDateTime, LocalDateTime> dateRange = Utils.calDateRange(ranges, startTime, endTime);
        if (dateRange == null) {
            return r;
        }

        String title = String.format("%s %s-%s", equipmentManage.getName(),
                dateRange.v1().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                dateRange.v2().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        r.put("title", title);
        Date startDate = Date.from(dateRange.v1().toInstant(ZoneOffset.of("+8")));
        Date endDate = Date.from(dateRange.v2().toInstant(ZoneOffset.of("+8")));
        switch (objType) {
            case 1:
                //电压
                r.putAll(getHistoryVoltage(equipmentManage, name, ranges, frequency, showType, startDate, endDate));
                break;
            case 2:
                //能量
                r.putAll(getHistoryEnergy(equipmentManage, name, ranges, frequency, showType, startDate, endDate));
                break;
            case 3:
                //电流
                r.putAll(getHistoryEfficiency(equipmentManage, name, ranges, frequency, showType, startDate, endDate));
                break;
            case 4:
                //温度
                r.putAll(getHistoryTemperature(equipmentManage, name, ranges, frequency, showType, startDate, endDate));
                break;
            case 5:
                //SOC
                r.putAll(getHistorySoc(equipmentManage, name, ranges, frequency, showType, startDate, endDate));
                break;
            case 6:
                //循环次数
                r.putAll(getHistoryCirc(equipmentManage, name, ranges, frequency, showType, startDate, endDate));
                break;
        }
        return r;
    }

    protected JSONObject queryDiagnose(String setVal, String equipmentId, String showType, String ranges, String frequency, Date startDate, Date endDate) {
        JSONObject r;
        String sql = "SELECT DATE_FORMAT(FROM_UNIXTIME((UNIX_TIMESTAMP(batch.`time`) DIV ($INTERVAL * 60)) * ($INTERVAL * 60)), '%d %H:%i') AS cal_time, $CAL_FUNC(result_val) AS val" +
                " FROM esms_diagnose_result_info info, esms_data_batch batch  WHERE " +
                " info.batch_id=batch.id AND info.set_val=? AND batch.time BETWEEN ? AND ? AND info.equipment_id=?";
        switch (frequency) {
            case "15":
                r = Utils.getFifteenMinutes();
                sql = sql.replace("$INTERVAL", "15");
                break;
            case "hour":
                r = Utils.getHour();
                sql = "SELECT DATE_FORMAT(FROM_UNIXTIME(batch.`time`), '%Y-%m-%d %H') AS cal_time, $CAL_FUNC(result_val) AS val" +
                        " FROM esms_diagnose_result_info info, esms_data_batch batch  WHERE " +
                        " info.batch_id=batch.id AND info.set_val=? AND batch.time BETWEEN ? AND ? AND info.equipment_id=?";
                break;
            case "day":
                r = Utils.getDay(ranges);
                sql = "SELECT DATE_FORMAT(FROM_UNIXTIME(batch.`time`), '%Y-%m-%d') AS cal_time, $CAL_FUNC(result_val) AS val" +
                        " FROM esms_diagnose_result_info info, esms_data_batch batch  WHERE " +
                        " info.batch_id=batch.id AND info.set_val=? AND batch.time BETWEEN ? AND ? AND info.equipment_id=?";
                break;
            case "month":
                r = Utils.getMonth();
                sql = "SELECT DATE_FORMAT(FROM_UNIXTIME(batch.`time`), '%Y-%m') AS cal_time, $CAL_FUNC(result_val) AS val" +
                        " FROM esms_diagnose_result_info info, esms_data_batch batch  WHERE " +
                        " info.batch_id=batch.id AND info.set_val=? AND batch.time BETWEEN ? AND ? AND info.equipment_id=?";
                break;
            default:
                r = new JSONObject();
                return r;
        }
        switch (showType) {
            case "now":
                sql = sql.replace("$CAL_FUNC", "");
            case "avg":
                sql = sql.replace("$CAL_FUNC", "avg");
                break;
            case "min":
                sql = sql.replace("$CAL_FUNC", "min");
                break;
            case "max":
                sql = sql.replace("$CAL_FUNC", "max");
                break;
        }
        Query qry = entityManager.createNativeQuery(sql);
        qry.setParameter(1, setVal);
        qry.setParameter(2, startDate);
        qry.setParameter(3, endDate);
        qry.setParameter(4, equipmentId);
        List<Object[]> result = qry.getResultList();
        for (Object[] rs : result) {
            if (rs[0] != null) {
                r.put((String) rs[0], rs[1]);
            }
        }
        return r;
    }

    protected JSONObject getHistoryEfficiency(EquipmentManage equipmentManage, String name, String ranges, String frequency, String showType, Date startDate, Date endDate) {
        ChartUtils.AggregationCondition condition = ChartUtils.buildCondition(frequency, ranges);
        JSONObject r = condition.defaultData;
        ESValueSourceAggregation aggregationBuilder = ChartUtils.getAggregation(showType);
        if (aggregationBuilder == null) {
            return r;
        }
        List<String> fieldNames = new ArrayList<>();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("macid", equipmentManage.getCode()));
        switch (name) {
            case "电流":
                fieldNames.add("BatCurrent");
                boolQueryBuilder.filter(QueryBuilders.existsQuery("BatCurrent"));
                break;
            default:
                return r;
        }

        elasticsearchService.aggregation(boolQueryBuilder
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                condition.interval, aggregationBuilder, (filedName, time, val) -> {
                    r.put(DateTimeFormat.forPattern(condition.fmt).print(time), val);
                }, fieldNames.toArray(new String[]{}));
        return r;
    }

    protected JSONObject getHistoryTemperature(EquipmentManage equipmentManage, String name, String ranges, String frequency, String showType, Date startDate, Date endDate) {
        ChartUtils.AggregationCondition condition = ChartUtils.buildCondition(frequency, ranges);
        JSONObject r = condition.defaultData;
        ESValueSourceAggregation aggregationBuilder = ChartUtils.getAggregation(showType);
        if (aggregationBuilder == null) {
            return r;
        }
        List<String> fieldNames = new ArrayList<>();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("macid", equipmentManage.getCode()));
        switch (name) {
            case "单体温度极值和极差":
                fieldNames.add("MaxTemp");
                fieldNames.add("MinTemp");
                boolQueryBuilder.filter(QueryBuilders.existsQuery("MaxTemp"));
                boolQueryBuilder.filter(QueryBuilders.existsQuery("MinTemp"));
                break;
            default:
                return r;
        }
        JSONObject rangeJson = new JSONObject();
        elasticsearchService.aggregation(boolQueryBuilder
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                condition.interval, aggregationBuilder, (filedName, time, val) -> {
                    String key = DateTimeFormat.forPattern(condition.fmt).print(time);
                    if (rangeJson.containsKey(key)) {
                        rangeJson.getJSONObject(key).put(filedName, val);
                    } else {
                        JSONObject json = new JSONObject();
                        json.put(filedName, val);
                        rangeJson.put(key, json);
                    }
                }, fieldNames.toArray(new String[]{}));
        r.putAll(rangeJson);
        return r;
    }

    protected JSONObject getHistoryVoltage(EquipmentManage equipmentManage, String name, String ranges, String
            frequency, String showType, Date startDate, Date endDate) {
        ChartUtils.AggregationCondition condition = ChartUtils.buildCondition(frequency, ranges);
        JSONObject r = condition.defaultData;
        ESValueSourceAggregation aggregationBuilder = ChartUtils.getAggregation(showType);
        if (aggregationBuilder == null) {
            return r;
        }
        List<String> fieldNames = new ArrayList<>();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("macid", equipmentManage.getCode()));
        switch (name) {
            case "总电压":
                fieldNames.add("BatVoltage");
                boolQueryBuilder.filter(QueryBuilders.existsQuery("BatVoltage"));
                break;
            case "单体电压极值和极差":
                boolQueryBuilder.filter(QueryBuilders.existsQuery("MinCellVolt"));
                fieldNames.add("MinCellVolt");
                fieldNames.add("MaxCellVolt");
                r.put("range", true);
                break;
            default:
                return r;
        }

        JSONObject rangeJson = new JSONObject();
        elasticsearchService.aggregation(boolQueryBuilder
                        .filter(QueryBuilders.rangeQuery("time").gte(startDate.getTime()).lte(endDate.getTime())),
                condition.interval, aggregationBuilder, (filedName, time, val) -> {
                    if (name.equals("单体电压极值和极差")) {
                        String key = DateTimeFormat.forPattern(condition.fmt).print(time);
                        if (rangeJson.containsKey(key)) {
                            rangeJson.getJSONObject(key).put(filedName, Utils.halfUp(val));
                        } else {
                            JSONObject json = new JSONObject();
                            json.put(filedName, Utils.halfUp(val));
                            rangeJson.put(key, json);
                        }
                    } else {
                        r.put(DateTimeFormat.forPattern(condition.fmt).print(time), Utils.halfUp(val));
                    }
                }, fieldNames.toArray(new String[]{}));
        r.putAll(rangeJson);
        return r;
    }

    protected JSONObject getHistorySoc(EquipmentManage equipmentManage, String name, String ranges, String frequency, String showType,
                                       Date startDate, Date endDate) {
        switch (name) {
            case "SOC":
                return this.queryDiagnose("soc", equipmentManage.getId(), showType, ranges, frequency, startDate, endDate);
        }
        return new JSONObject();
    }

    protected JSONObject getHistoryCirc(EquipmentManage equipmentManage, String name, String ranges, String frequency, String showType,
                                        Date startDate, Date endDate) {
        switch (name) {
            case "循环次数":
                return this.queryDiagnose("xhcs", equipmentManage.getId(), showType, ranges, frequency, startDate, endDate);
        }
        return new JSONObject();
    }

    protected JSONObject getHistoryEnergy(EquipmentManage equipmentManage, String name, String ranges, String frequency, String showType,
                                          Date startDate, Date endDate) {
        switch (name) {
            case "可储存电量":
                return this.queryDiagnose("kccdl", equipmentManage.getId(), showType, ranges, frequency, startDate, endDate);
            case "总电量":
                return this.queryDiagnose("kccdl", equipmentManage.getId(), showType, ranges, frequency, startDate, endDate);
        }
        return new JSONObject();
    }
}
